<template>
  <el-card>
    <el-breadcrumb separator="/">
      <el-breadcrumb-item :to="{ path:'/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>用户管理</el-breadcrumb-item>
      <el-breadcrumb-item>用户列表</el-breadcrumb-item>
    </el-breadcrumb>

    <el-row :gutter="20">
      <el-col :span='21'>
        <el-input v-model="query.keyword"
                  placeholder="请输入用户名或昵称"
                  size="default"
                  autocomplete="off"
                  clearable
                  @input="selectAllUser"
                  >
          <template #prefix>
            <el-icon><Search/></el-icon>
          </template>
        </el-input>

      </el-col>
      <el-col :span='3'>
        <el-button type="primary" @click='addUserDialog'  :disabled="userBtnIsDisable.addBtn">添加用户</el-button>
      </el-col>
    </el-row>
    <!--表格数据-->
    <el-table :data="tableData" border style="width: 100%" stripe>
      <el-table-column label="序列" width="60" type="index"></el-table-column>
      <el-table-column prop="username" label="账号" width="120"/>
      <el-table-column prop="nickname" label="昵称" width="120"/>
      <el-table-column prop="email" label="邮箱" width="250"/>
      <el-table-column prop="phoneNumber" label="手机号" width="120"/>
      <el-table-column prop="status" label="状态" width="100">
        <template v-slot:='scope'>
            <el-switch v-model="scope.row.status" @change="updateUserStatus(scope.row.status,scope.row.id)"/>
        </template>
      </el-table-column>
      <el-table-column prop="role" label="角色" width="120"/>
      <el-table-column label="操作">
        <template v-slot:="scope">
          <el-button type="primary" :icon="Edit" size='small' :disabled="userBtnIsDisable.editBtn" @click="editUserShow(scope.row.id)">编辑</el-button>
          <el-button type="danger"  :icon="Delete" size='small' :disabled="userBtnIsDisable.deleteBtn" @click="deleteUser(scope.row.id)">删除</el-button>
          <el-button type="warning" :icon="Setting" size='small' :disabled="userBtnIsDisable.editBtn" @click="updateUserRole(scope.row.id)">分配角色</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!--分页-->
    <el-pagination
        v-show="isPaginationShow"
        @size-change="handlePageSizeChange"
        @current-change="handleCurrentPageChange"
        background
        layout="prev,pager,next,total,sizes,jumper"
        v-model:current-page="query.currentPage"
        v-model:page-size="query.pageSize"
        :page-sizes="[5,9]"
        :total="total">
    </el-pagination>

    <!--添加用户-->
    <el-dialog v-model="addUserDialogVisible"
               title="添加用户"
               width="32%"
               :before-close="handleClosed">
      <el-form :rules="addUserRules" :model="addUser" ref="addUserRef" status-icon>
        <!--用户名-->
        <el-form-item prop="username" label="用户名" label-width="70">
          <el-input v-model="addUser.username"
                    class="w-50 m-2"
                    placeholder="请输入用户名"
                    size="large"
                    autocomplete="off"
                    clearable validate-event>
          </el-input>
        </el-form-item>
        <!--密码-->
        <el-form-item prop="password" label="密码" label-width="70">
          <el-input v-model="addUser.password"
                    class="w-50 m-2"
                    type="password"
                    placeholder="请输入6~13位密码"
                    minlength="6"
                    maxlength="13"
                    size="large"
                    autocomplete="off"
                    show-password clearable validate-event>
          </el-input>
        </el-form-item>
        <!--校验密码-->
        <el-form-item prop="reenterPassword" label="密码" label-width="70">
          <el-input v-model="addUser.reenterPassword"
                    class="w-50 m-2"
                    type="password"
                    placeholder="请再次输入新密码"
                    minlength="6"
                    maxlength="13"
                    size="large"
                    autocomplete="off"
                    show-password clearable validate-event>
          </el-input>
        </el-form-item>
        <!--昵称-->
        <el-form-item prop="nickname" label="昵称" label-width="70">
          <el-input v-model="addUser.nickname"
                    class="w-50 m-2"
                    placeholder="请输入昵称"
                    size="large"
                    autocomplete="off"
                    clearable validate-event>
          </el-input>
        </el-form-item>

        <!--电话号码-->
        <el-form-item prop="phoneNumber" label="手机号" label-width="70">
          <el-input v-model="addUser.phoneNumber"
                    class="w-50 m-2"
                    placeholder="请输入手机号"
                    size="large"
                    autocomplete="off"
                    clearable validate-event>
          </el-input>
        </el-form-item>

        <!--邮箱-->
        <el-form-item prop="email" label="邮箱" label-width="70">
          <el-input v-model="addUser.email"
                    type="email"
                    class="w-50 m-2"
                    placeholder="请输入邮箱"
                    size="large"
                    autocomplete="off"
                    clearable validate-event>
          </el-input>
        </el-form-item>

        <!--角色-->
        <el-form-item prop="role" label="角色" label-width="70">
          <el-select v-model="addUser.role"
                     filterable
                     validate-event
                     class="m-2"
                     placeholder="请选择角色"
                     style="width: 300px">

                    <el-option label="请选择角色"/>
                    <el-option
                     v-for="option in roleOptions"
                     :key="option.id"
                     :label="option.roleName"
                     :value="option.id"
                    />
          </el-select>
        </el-form-item>
      </el-form>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="closeDialog">取消</el-button>
          <el-button type="primary" @click="submitAddUserForm(addUserRef)">提交</el-button>
        </span>
      </template>
    </el-dialog>

    <!--编辑用户-->
    <el-dialog v-model="editUserDialogVisible"
               title="编辑用户"
               width="32%"
               :before-close="handleEditUserClosed">
      <el-form :rules="editUserRules" :model="editUser" ref="editUserRef" status-icon>
        <!--昵称-->
        <el-form-item prop="nickname" label="昵称" label-width="70">
          <el-input v-model="editUser.nickname"
                    class="w-50 m-2"
                    placeholder="请输入昵称"
                    size="large"
                    autocomplete="off"
                    clearable validate-event>
          </el-input>
        </el-form-item>

        <!--电话号码-->
        <el-form-item prop="phoneNumber" label="手机号" label-width="70">
          <el-input v-model="editUser.phoneNumber"
                    class="w-50 m-2"
                    placeholder="请输入手机号"
                    size="large"
                    autocomplete="off"
                    clearable validate-event>
          </el-input>
        </el-form-item>

        <!--邮箱,可能没有这个类型-->
        <el-form-item prop="email" label="邮箱" label-width="70">
          <el-input v-model="editUser.email"
                    type="email"
                    class="w-50 m-2"
                    placeholder="请输入邮箱"
                    size="large"
                    autocomplete="off"
                    clearable validate-event>
          </el-input>
        </el-form-item>
      </el-form>

      <template #footer>
      <span class="dialog-footer">
        <el-button @click="closeEditUserDialog">取消</el-button>
        <el-button type="primary" @click="submitEditUserForm(editUserRef)">提交</el-button>
      </span>
      </template>
    </el-dialog>

    <!--分配角色-->
    <el-dialog v-model="editUserRoleDialogVisible"
               title="分配用户角色"
               width="30%"
               :before-close="handleEditUserRoleClosed">
      <el-form :rules="editUserRoleRules" :model="editUserRole" ref="editUserRoleRef" status-icon>
        <!--角色-->
        <el-form-item prop="role" label="角色">
          <el-select v-model="editUserRole.role"
                     validate-event
                     filterable
                     class="m-2"
                     placeholder="请选择角色"
                     style="width: 300px">

            <el-option label="请选择角色"/>

            <el-option
                v-for="option in roleOptions"
                :key="option.roleId"
                :label="option.roleName"
                :value="option.roleId"/>
          </el-select>
        </el-form-item>
      </el-form>

      <template #footer>
      <span class="dialog-footer">
        <el-button @click="closeEditUserRoleDialog">取消</el-button>
        <el-button type="primary" @click="submitEditUserRoleForm(editUserRoleRef)">提交</el-button>
      </span>
      </template>
    </el-dialog>

  </el-card>
</template>

<script setup>
import {reactive, ref, onMounted, getCurrentInstance, computed } from "vue";
import { Delete,Edit,Setting,Search } from "@element-plus/icons-vue";
import axios from "axios";
const msg = getCurrentInstance().appContext.config.globalProperties.$message
const confirm=getCurrentInstance().appContext.config.globalProperties.$confirm

//分页组件是否显示
const isPaginationShow=computed(()=>{
  return total.value > 0;
});

//登陆进去不能编辑自己的数据

//表格数据
let tableData=ref([]);

//查询条件
let query=reactive({
  keyword:"",
  currentPage: 1,
  pageSize: 9
})

//数据总条数
let total=ref(0);

//按钮是否禁用
let userBtnIsDisable=reactive({
  addBtn: false,
  editBtn: false,
  deleteBtn: false
})

//获取所有的用户数据
function selectAllUser(){
  const options = {
    //获取用户信息和权限信息
    url: '/user/selectAllUser',
    params:{
      keyword: query.keyword,
      currentPage:query.currentPage,
      pageSize:query.pageSize
    },
    method: 'GET',
    headers: {'Content-Type': 'application/json'}
  };

  axios(options).then(res => {
    let mg = res.data;
    if (mg.meta.code == 200) {
      //将值赋值给tableData
      tableData.value=mg.data.users;
      total.value=mg.data.total;
    } else {
      msg.error(mg.meta.msg);
    }
  }).catch(err => {
    //网络异常啥的
    msg.error(err);
  })
}

//获取该用户所具有的三级权限信息
function selectUserAllAuthority(){
  const options = {
    url: '/user/findUserAllAuthority',
    method: 'GET',
    headers: {'Content-Type': 'application/json'}
  };

  axios(options).then(res => {
    let mg = res.data;
    if (mg.meta.code == 200) {
      //返回数据是一个数组
      const authoryArr=mg.data;
      //判断数组中是否含有某个字符
      if(!authoryArr.includes("AddUser")){
        userBtnIsDisable.addBtn= true;
      }

      if(!authoryArr.includes("UpdateUser")){
        userBtnIsDisable.editBtn=true;
      }

      if(!authoryArr.includes("SelectUser")){
        userBtnIsDisable.searchBtn=true;
      }

      if(!authoryArr.includes("DeleteUser")){
        userBtnIsDisable.deleteBtn=true;
      }

    } else {
      //其他问题
      msg.error(mg.meta.msg);
    }
  }).catch(err => {
    //网络异常啥的
    msg.error(err);
  })
}

//挂在完毕之后初始话数据
onMounted(()=>{
  selectAllUser();
  selectUserAllAuthority();
})

//每页条数改变时触发的事件
const handlePageSizeChange=(val)=>{
  query.pageSize=val;
  selectAllUser();
}

//当前页码改变时触发的事件
const handleCurrentPageChange=(val)=>{
  query.currentPage=val;
  selectAllUser();
}

//添加用户对话框是否显示
const addUserDialogVisible=ref(false);

//添加用户对话框数据
let addUser=reactive({
  username:"",
  password:"",
  nickname:"",
  phoneNumber:"",
  email:"",
  role:""
})

//角色列表
let roleOptions=ref([])

//校测密码的强度
const checkPasswordStrength = (rule, value, callback) => {
  /*
  * (?=.*\d):至少有一个数字
  * (?=.*[a-z]):至少有一个小写字母
  * (?=.*[A-Z]):至少有一个大写字母
  * (?=.*[~!@#$%^&+=]):至少有一个特殊字符(这里列举了一些常见的特殊字符)
  * (?=\S+$):没有空白字符(这个要求可能是不必要的，除非你的需求中有特别强调)
  * .{6,13}:至少有6个字符长
  * */
  const reg=/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&+=])(?=\S+$).{6,13}/
  // 新密码必须由a-zA-Z0-9~!@#$%^&+=等符号组成的6～13个字符
  if(addUser.password.match(reg)){
    return callback()
  }
  callback(new Error('密码必须包含数字，大小写字母以及(~!@#$%^&+=)括号中的任意一个字符'))
}

//再次输入的新密码必须与第一次输入的新密码一致
const checkReenterPassword = (rule, value, callback) => {
  //两次输入的新密码必须一致
  if(addUser.reenterPassword == addUser.password){
    return callback()
  }
  callback(new Error('两次密码不一致，请重新输入密码!'))
}

//校验邮箱规则
const checkEmail = (rule,value,callback) =>{
  const reg=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
  if(addUser.email.match(reg)){
    return callback();
  }
  callback(new Error('邮箱不符合要求，请重新输入!'))
}

//校验手机号码
const checkPhoneNumber= (rule,value,callback) =>{
  //const reg=/^[1][3,4,5,7,8][0-9]{9}$/;
  const reg=/^1\d{10}$|^(0\d{2,3}-?|\(0\d{2,3}\))?[1-9]\d{4,7}(-\d{1,8})?$/;
  if(addUser.phoneNumber.match(reg)){
    return callback();
  }
  callback(new Error('手机号格式不符合要求，请重新输入!'))
}

//添加用户校验规则
const addUserRules=reactive({
  username:[
    {
      required:true,
      message: '用户名不能为空!',
      trigger: 'blur'
    },
    {
      min: 2,
      max: 10,
      message: '用户名长度必须在2～10位',
      trigger: 'blur'
    }
  ],
  password:[
    {
      required:true,
      message: '密码不能为空!',
      trigger: 'blur'
    },
    {
      min: 6,
      max: 13,
      message: '密码长度必须在6～13位',
      trigger: 'blur'
    },
    {
      validator:checkPasswordStrength,
      trigger: 'blur'
    }
  ],
  reenterPassword:[
    {
      required:true,
      message: '密码不能为空!',
      trigger: 'blur'
    },
    {
      min: 6,
      max: 13,
      message: '密码长度必须在6～13位',
      trigger: 'blur'
    },
    {
      validator:checkReenterPassword,
      trigger: 'blur'
    }
  ],
  nickname:[
    {
      required:true,
      message: '昵称不能为空!',
      trigger: 'blur'
    },
    {
      min: 2,
      max: 10,
      message: '昵称长度必须在2～10位',
      trigger: 'blur'
    }
  ],
  phoneNumber:[
    {
      required:true,
      message: '手机号不能为空!',
      trigger: 'blur'
    },
    {
      validator:checkPhoneNumber,
      trigger: 'blur'
    }
  ],
  email:[
    {
      required:true,
      message: '邮箱不能为空!',
      trigger: 'blur'
    },
    {
      validator:checkEmail,
      trigger: 'blur'
    }
  ],
  role:[
    {
      required:true,
      message: '角色不能为空!',
      trigger: 'blur'
    }
  ]
})

//查询所有的角色信息放入roleOptions中
function findAllRole(){
  //查询所有角色信息
  const options = {
    url: '/role/selectRoles',
    method: 'GET',
    headers: {'Content-Type': 'application/json'}
  };

  axios(options).then(res => {
    let mg = res.data;
    if (mg.meta.code == 200) {
      roleOptions.value=mg.data;
    } else {
      //密码不对或者其他问题
      msg.error(mg.meta.msg);
    }
  }).catch(err => {
    //网络异常啥的
    msg.error(err);
  })
}

//添加用户对话框
function addUserDialog(){
  //查询所有的角色信息放入roleOptions中
  findAllRole();
  //将对话框打开
  addUserDialogVisible.value=true;
}

//添加用户表单引用
let addUserRef=ref();

//关闭添加用户对话框，并且重置添加用户表单
function closeDialog(){
  addUserRef.value.resetFields();
  addUserDialogVisible.value=false;
}

//关闭添加用户对话框，并且重置添加用户表单
function handleClosed(){
  closeDialog();
}

//添加用户表单提交
function submitAddUserForm(addUserRef){
  addUserRef.validate(async validate =>{
    if (!validate) return
    //更改密码的数据
    const options = {
      url: '/user/addUser',
      method: 'post',
      data: {
        username:addUser.username,
        password:addUser.password,
        nickname:addUser.nickname,
        email:addUser.email,
        phoneNumber:addUser.phoneNumber,
        roleId:parseInt(addUser.role+'')
      },
      headers: {'Content-Type': 'application/json'}
    };

    axios(options).then(res => {
      let mg = res.data;
      if (mg.meta.code == 200) {
        selectAllUser();
        //添加用户成功！
        msg.success(mg.meta.msg);
        //关闭添加用户对话框
        closeDialog();
      } else {
        msg.error(mg.meta.msg);
      }
    }).catch(err => {
      //网络异常啥的
      msg.error(err);
    })
  });
}

//更新用户状态
const updateUserStatus=(val,id)=>{
  //为true时，下线，为0时上线
  let status = val ? 1 : 0;
  const options = {
    url: '/user/updateUserStatus',
    method: 'put',
    data: {
      id: id,
      status: status
    },
    headers: {'Content-Type': 'application/json'}
  };

  axios(options).then(res => {
    let mg = res.data;
    if (mg.meta.code !== 200) {
      msg.error(mg.meta.msg);
    }
  }).catch(err => {
    //网络异常啥的
    msg.error(err);
  })
}

//编辑对话框是否可见
let editUserDialogVisible=ref(false);

//校验邮箱规则
const checkEditUserEmail = (rule,value,callback) =>{
  const reg=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
  if(editUser.value.email.match(reg)){
    return callback();
  }
  callback(new Error('邮箱不符合要求，请重新输入!'))
}

//校验手机号码
const checkEditUserPhoneNumber= (rule,value,callback) =>{
  //const reg=/^[1][3,4,5,7,8][0-9]{9}$/;
  const reg=/^1\d{10}$|^(0\d{2,3}-?|\(0\d{2,3}\))?[1-9]\d{4,7}(-\d{1,8})?$/;
  if(editUser.value.phoneNumber.match(reg)){
    return callback();
  }
  callback(new Error('手机号格式不符合要求，请重新输入!'))
}

//编辑用户对话框规则
let editUserRules=reactive({
  nickname:[
    {
      required:true,
      message: '昵称不能为空!',
      trigger: 'blur'
    },
    {
      min: 2,
      max: 10,
      message: '昵称长度必须在2～10位',
      trigger: 'blur'
    }
  ],
  phoneNumber:[
    {
      required:true,
      message: '手机号不能为空!',
      trigger: 'blur'
    },
    {
      validator:checkEditUserPhoneNumber,
      trigger: 'blur'
    }
  ],
  email:[
    {
      required:true,
      message: '邮箱不能为空!',
      trigger: 'blur'
    },
    {
      validator:checkEditUserEmail,
      trigger: 'blur'
    }
  ]
})

//编辑用户对话框数据
let editUser=ref({
  id:"",
  nickname:"",
  phoneNumber:"",
  email:""
})

//编辑用户对话框引用
let editUserRef=ref();

//关闭编辑用户对话框
function handleEditUserClosed(){
  editUserRef.value.resetFields();
  editUserDialogVisible.value=false;
}

//关闭编辑用户对话框
function closeEditUserDialog(){
  handleEditUserClosed();
}

//编辑用户
function editUserShow(id){
  //从数据库查询用户信息
  axios.get("/user/selectSingleUser/"+id).then(res=>{
    let mg = res.data;
    if (mg.meta.code == 200) {
      editUser.value=mg.data
    } else {
      msg.error(mg.meta.msg);
    }
  }).catch(e=>{
    msg.error(e.error);
  });
  editUserDialogVisible.value=true;
}

//提交编辑用户对话框数据
function submitEditUserForm(editUserRef){
  editUserRef.validate(async validate =>{
    if (!validate) return
    //更改密码的数据
    const options = {
      url: '/user/updateUser',
      method: 'put',
      data: {
        id:editUser.value.id,
        nickname:editUser.value.nickname,
        email:editUser.value.email,
        phoneNumber:editUser.value.phoneNumber
      },
      headers: {'Content-Type': 'application/json'}
    };

    axios(options).then(res => {
      let mg = res.data;
      if (mg.meta.code == 200) {
        tableData.value.forEach((user,index)=>{
           if(user.id == editUser.value.id){
              tableData.value[index]=mg.data; //更新的数据
           }
        });

        //编辑用户成功！
        msg.success(mg.meta.msg);
        //关闭编辑用户对话框
        closeEditUserDialog();
      } else {
        msg.error(mg.meta.msg);
      }
    }).catch(err => {
      //网络异常啥的
      msg.error(err);
    })
  });
}

//删除用户
async function deleteUser(id){
  // 弹框询问用户是否删除
  const confirmResult = await confirm('此操作将永久删除该用户, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).catch(err => err)
  // 如果用户确认删除，则返回字符串confirm
  // 如果用户取消了删除，则返回字符串cancel
  if (confirmResult !== 'confirm') {
    return msg.info('用户取消删除！');
  }

  axios.delete("/user/deleteUser/"+id).then(res => {
    let mg = res.data;
    if (mg.meta.code == 200) {
      let tempIndex=0;
      tableData.value.forEach((user,index)=>{
        if(user.id==id){
          tempIndex=index;
        }
      })
      tableData.value.splice(tempIndex,1);
      total.value=total.value-1;
    }
  }).catch(err =>{
    msg.error(err);
  })
}

//编辑用户角色对话框是否可视
let editUserRoleDialogVisible=ref(false);

let editUserRoleRef=ref();

//编辑用户角色校验规则
const editUserRoleRules=({
  role:[
    {
      required:true,
      message: '角色不能为空!',
      trigger: 'blur'
    }
  ]
});

//编辑用户角色对话框数据
let editUserRole=ref({
  id:"",
  role:"SuperAdmin"
});

//打开编辑用户角色对话框并显示
function updateUserRole(id){
  //查询用户所具有的角色
  findRoleById(id)
  //查询所有角色
  findAllRole();
  editUserRoleDialogVisible.value=true;
}

//关闭编辑用户角色对话框
function handleEditUserRoleClosed(){
  editUserRoleRef.value.resetFields();
  editUserRoleDialogVisible.value = false;
}

//关闭编辑用户角色对话框
function closeEditUserRoleDialog(){
  handleEditUserRoleClosed();
}

//根据用户id查询用户所具有的角色
function findRoleById(id){
  axios.get("/user/selectUserRole/"+id)
      .then(res=>{
          let roleData=res.data
          if(roleData.meta.code==200){
            editUserRole.value.role=roleData.data;
            editUserRole.value.id=id;
          }
      }).catch(error=>{
        msg.error(error);
  })
}

//提交重新选择的角色数据
function submitEditUserRoleForm(editUserRoleRef){
  editUserRoleRef.validate(async validate =>{
    if (!validate) return
    //更改密码的数据
    const options = {
      //发送ajax数据，需要修改更新数据
      url: '/user/updateUserRole',
      method: 'put',
      data: {
        id:editUserRole.value.id,
        roleId:parseInt(editUserRole.value.role),
      },
      headers: {'Content-Type': 'application/json'}
    };

    axios(options).then(res => {
      let mg = res.data;
      if (mg.meta.code == 200) {

        tableData.value.forEach((user,index)=>{
          if(user.id == editUserRole.value.id){
            tableData.value[index]=mg.data; //更新的数据
          }
        });

        //编辑用户成功！
        msg.success(mg.meta.msg);
        //关闭编辑用户角色对话框
        closeEditUserRoleDialog();
      } else {
        msg.error(mg.meta.msg);
      }
    }).catch(err => {
      //网络异常啥的
      msg.error(err);
    })
  });
}

</script>

<style scoped>
  .el-row{
    margin: 20px 0;
  }
  .el-input{
    --el-input-width: 300px;
  }
  .el-pagination{
    margin-top: 20px;
    justify-content: center;
  }
</style>
